#include "pin.h"

#define DBGBUG_TAG "pin"
#include "debug.h"

static mt_pin_t *hw_pin;

mt_err_t mt_pin_config(mt_uint32_t logic_pin, mt_uint32_t mode, mt_uint32_t pull)
{
    MT_ASSERT(hw_pin == MT_NULL);
    MT_ASSERT(hw_pin->parent.magic != PIN_MAGIC);
    
    if(hw_pin->ops->pin_config == MT_NULL)
        return MT_ENOSYS;
    
    return hw_pin->ops->pin_config(logic_pin, mode, pull);
}

mt_int32_t mt_pin_read(mt_uint32_t logic_pin)
{
    MT_ASSERT(hw_pin == MT_NULL);
    MT_ASSERT(hw_pin->parent.magic != PIN_MAGIC);
    
    if(hw_pin->ops->pin_read == MT_NULL)
        return MT_ENOSYS;
    
    return hw_pin->ops->pin_read(logic_pin);
}

mt_err_t mt_pin_write(mt_uint32_t logic_pin, mt_int32_t val)
{
    MT_ASSERT(hw_pin == MT_NULL);
    MT_ASSERT(hw_pin->parent.magic != PIN_MAGIC);
    
    if(hw_pin->ops->pin_write == MT_NULL)
        return MT_ENOSYS;
    
    return hw_pin->ops->pin_write(logic_pin, val);
}

mt_err_t mt_pin_attach_irq(mt_uint32_t logic_pin, mt_pin_callbk callbk, void *arg)
{
    MT_ASSERT(hw_pin == MT_NULL);
    MT_ASSERT(hw_pin->parent.magic != PIN_MAGIC);
    
    if(hw_pin->ops->pin_attach_irq == MT_NULL)
        return MT_ENOSYS;
    
    return hw_pin->ops->pin_attach_irq(logic_pin, callbk, arg);
}

mt_err_t mt_pin_dettach_irq(mt_uint32_t logic_pin)
{
    MT_ASSERT(hw_pin == MT_NULL);
    MT_ASSERT(hw_pin->parent.magic != PIN_MAGIC);
    
    if(hw_pin->ops->pin_dettach_irq == MT_NULL)
        return MT_ENOSYS;
    
    return hw_pin->ops->pin_dettach_irq(logic_pin);
}

mt_err_t mt_pin_enable_irq(mt_uint32_t logic_pin, mt_int32_t enable)
{
    MT_ASSERT(hw_pin == MT_NULL);
    MT_ASSERT(hw_pin->parent.magic != PIN_MAGIC);
    
    if(hw_pin->ops->pin_enable_irq == MT_NULL)
        return MT_ENOSYS;
    
    return hw_pin->ops->pin_enable_irq(logic_pin, enable);
}

static mt_err_t _mt_pin_ctrl(mt_device_t *device, mt_uint32_t cmd, void *arg)
{
    mt_pin_config_t *pin_config;
    mt_pin_t *pin = mt_container_of(device, mt_pin_t, parent);
    
    MT_ASSERT(arg == MT_NULL);
    
    if(pin->ops->pin_config == MT_NULL)
        return MT_ENOSYS;
    
    pin_config = arg;
    return pin->ops->pin_config(pin_config->logic_pin, pin_config->mode, pin_config->pull);
}

static mt_ssize_t _mt_pin_read(mt_device_t *device, void *buffer, mt_size_t size, mt_uint32_t pos)
{
    mt_uint32_t logic_pin;
    mt_uint32_t *value;
    mt_pin_t *pin = mt_container_of(device, mt_pin_t, parent);

    if(pin->ops->pin_read == MT_NULL)
        return MT_ENOSYS;
    
    logic_pin = pos;
    value = buffer;
    *value = pin->ops->pin_read(logic_pin);
    if((*value == PIN_LOW) || (*value == PIN_HIGH))
        return size;
    else
        return MT_EIO;
}

static mt_ssize_t _mt_pin_write(mt_device_t *device, const void *buffer, mt_size_t size, mt_uint32_t pos)
{
    mt_err_t result;
    mt_uint32_t logic_pin;
    const mt_uint32_t *value;
    mt_pin_t *pin = mt_container_of(device, mt_pin_t, parent);

    if(pin->ops->pin_write == MT_NULL)
        return MT_ENOSYS;
    
    logic_pin = pos;
    value = buffer;
    result = pin->ops->pin_write(logic_pin, *value);
    if(result == MT_EOK)
        return size;
    else
        return result;
}

static mt_device_ops_t pin_ops =
{
    .init = MT_NULL,
    .open = MT_NULL,
    .close = MT_NULL,
    .ioctl = _mt_pin_ctrl,
    .pread = _mt_pin_read,
    .pwrite = _mt_pin_write,
};

mt_err_t mt_pin_register(mt_pin_t *pin, const char *name)
{
    mt_err_t result;
    
    MT_ASSERT(pin == MT_NULL);
    MT_ASSERT(name == MT_NULL);
    MT_ASSERT(pin->ops == MT_NULL);
    
    hw_pin = pin;
    hw_pin->parent.flags = MT_DEVICE_RDWR;
    hw_pin->parent.magic = PIN_MAGIC;
    hw_pin->parent.ops = &pin_ops;
    result = mt_device_register(&hw_pin->parent, name);
    if(result != MT_EOK)
        LOG_E("register pin device faied\r\n");

    return result;
}
